package org.runecore.rs2;

import java.util.ArrayDeque;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Queue;

import org.runecore.rs2.model.Entity;


/**
 * EntityList.java
 * RuneCore 614
 * @author Matt Bishop
 */
public class EntityList<E extends Entity> implements Iterable<E> {

	/**
	 * An array of entities
	 */
	private final Entity[] entities;
	
	/**
	 * A queue of valid indices
	 */
	private Queue<Integer> validIndices;

	/**
	 * Size of the entity list
	 */
	private int size = 0;
	
	/**
	 * Constructor
	 * @param capacity The max value of entitys allowed
	 */
	public EntityList(int capacity) {
		entities = new Entity[capacity+1]; // do not use idx 0
		validIndices = new ArrayDeque<Integer>(capacity);
		for (int i =1; i< capacity+1; i++)
			validIndices.add(i);
	}
	
	/**
	 * Get's an entity from the list
	 * @param index The index of the entity to return
	 * @return The entity
	 */
	@SuppressWarnings("unchecked")
	public E get(int index) {
		if(index <= 0 || index >= entities.length) {
			throw new IndexOutOfBoundsException();
		}
		return (E) entities[index];
	}
		
	/**
	 * Add's an entity to the list 
	 * @param entity The entity to addd
	 * @return If it was successful
	 */
	public boolean add(E entity) {
		if(validIndices.peek() == null)
			return false;
		int i = validIndices.poll();
		entities[i] = entity;
		entity.setIndex(i);
		size++;
		return true;
	}

	/**
	 * Checks if the list contains the entity
	 * @param entity The entity to check for
	 * @return If it contains it
	 */
	public boolean contains(E entity) {
		return entities[entity.getIndex()] != null;
	}

	/**
	 * The iterator for the list
	 */
	@Override
	public Iterator<E> iterator() {
		return new EntityListIterator();
	}

	/**
	 * Removes an entity
	 * @param entity The entity to remove
	 * @return If it was successful
	 */
	public boolean remove(E entity) {
		if((entity != null) && entities[entity.getIndex()] == entity) {
			entities[entity.getIndex()] = null;
			validIndices.offer(entity.getIndex());
			size--;
			return true;
		}
		return false;
	}
	
	/**
	 * Removes an entity by index
	 * @param i The index of the entity 
	 * @return If it was successful
	 */
	public boolean remove(int i) {
		if(entities[i] != null) {
			entities[i] = null;
			validIndices.offer(i);
			size--;
			return true;
		}
		return false;
	}

	/**
	 * Gets the size of the entity list
	 * @return The size of the list
	 */
	public int size() {
		return size;
	}
	
	/**
	 * EntityList.java
	 * RuneCore 614
	 * @author Matt Bishop
	 */
	public class EntityListIterator implements Iterator<E> {

		/**
		 * Last index
		 */
		private int lastIndex = -1;

		/**
		 * Where you start iterating from
		 */
		private int cursor = 0;

		/**
		 * Does the iterator have another entity?
		 */
		@Override
		public boolean hasNext() {
			for (int i = cursor; i < entities.length; i++) {
				if (entities[i] != null)
					return true;
			}
			return false;
		}

		/**
		 * Returns the next entity
		 */
		@SuppressWarnings("unchecked")
		@Override
		public E next() {
			for (int i = cursor; i < entities.length; i++) {
				if (entities[i] != null) {
					lastIndex = i;
					cursor = i + 1;
					return (E) entities[i];
				}
			}

			throw new NoSuchElementException();
		}

		/**
		 * Removes the entity
		 */
		@SuppressWarnings("unchecked")
		@Override
		public void remove() {
			if (lastIndex != -1) {
				E entity = (E) entities[lastIndex];
				entity.setIndex(-1);
				entities[lastIndex] = null;
				lastIndex = -1;
			}

			throw new IllegalStateException();
		}
	}
	
}